1 using System;
2 using
System.Collections.Generic;
3 using
System.ComponentModel;
4 using
System.Data;
5 using
System.Drawing;
6 using
System.Text;
7 using
System.Windows.Forms;
8 using
System.Drawing.Printing;
9
10 namespace
VietGraph
11 {
12     
public enum GraphMode
13     { Rectangular, Polar };
14
15     
//[ToolboxBitmap("graph.bmp")]
16     
public partial class ExpressionPlotter : Control
17     {
18
19         
#region MemberVariables
20
21         
int iLengthScale; //represents no. of pixels for a scale
22         
int iOriginX, iOriginY; //represents the location of origin
23
24         
double dScaleX = 10, dScaleY = 10; //base scale for graph
25         
double dForwardX = 0, dForwardY = 0; //position related to base scale
26
27         
int iDivisionsX = 5, iDivisionsY = 5;
28
29         
int iLengthBox;
30         
int iPrintStepX = 1;
31         
int iPrintStepY = 1;
32         
int iControlSize = 0;
33         
int iPenWidth = 1;
34
35         
bool bGrids = false;
36         
bool bDisplayText = true;
37
38         
int iPolarSensitivity = 100;
39
40         GraphMode graphMode = GraphMode.Rectangular;
41         PrintDocument printDoc;
42
43         List<IEvaluatable> expressions;
44         List<Color> expColors;
45         List<
bool> expVisible;
46
47         
#endregion
48
49         
#region Control specific functions
50         
public ExpressionPlotter()
51         {
52             
this.expressions = new List<IEvaluatable>();
53             
this.expColors = new List<Color>();
54             
this.expVisible = new List<bool>();
55             InitializeComponent();
56         }
57
58         
protected override void OnPaint(PaintEventArgs pe)
59         {
60             
//update internal variables
61             UpdateVariables();
62
63             pe.Graphics.Clear(Color.White);
64             pe.Graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
65             pe.Graphics.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceOver;
66             pe.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
67             PlotGraph(pe.Graphics);
68
69             
// Calling the base class OnPaint
70             
base.OnPaint(pe);
71         }
72
73         
//private void ExpressionPlotter_Resize(object sender, EventArgs e)
74         
//{
75         
// //code to keep the control's height and width same
76
77         
// //see whether width was changed or the height was changed
78         
// if (iControlSize != this.Width)
79         
// this.Height = this.Width; //width was changed so adjust height accordingly
80         
// else
81         
// this.Width = this.Height; //height was changed so adjust width accordingly
82         
//}
83
84         
private void UpdateVariables()
85         {
86             iControlSize =
this.Height;
87             iLengthScale = (
int)(iControlSize / 2.25);
88             iOriginX = (
this.Width) / 2;
89             iOriginY = (
this.Height) / 2;
90             
if (bGrids == true)
91                 
this.iLengthBox = this.iLengthScale;
92             
else
93                 
this.iLengthBox = (int)(this.iLengthScale * 0.025);
94         }
95         
private double IncreaseScale(double scale)
96         {
97             
double absScale = Math.Round(Math.Abs(scale), 3);
98             
double newScale;
99             
if (absScale >= 100)
100                 newScale = (absScale +
100);
101             
else if (absScale >= 10)
102                 newScale = (absScale +
10);
103             
else if (absScale >= 1)
104                 newScale = (absScale +
1);
105             
else if (absScale >= .10)
106                 newScale = (absScale + .
10);
107             
else
108                 newScale = (absScale + .
010);
109             
return newScale * Math.Sign(scale);
110         }
111         
private double DecreaseScale(double scale)
112         {
113             
double absScale = Math.Round(Math.Abs(scale), 3);
114             
double newScale;
115             
if (absScale > 100)
116                 newScale = (absScale -
100);
117             
else if (absScale > 10)
118                 newScale = (absScale -
10);
119             
else if (absScale > 1)
120                 newScale = (absScale -
1);
121             
else if (absScale > .1)
122                 newScale = (absScale - .
1);
123             
else if (absScale > .01)
124                 newScale = (absScale - .
01);
125             
else
126                 newScale = absScale;
127             
return newScale * Math.Sign(scale);
128         }
129
130         
#endregion
131
132         
#region Properties
133         
public int DivisionsX
134         {
135             
get { return this.iDivisionsX; }
136             
set { if (value > 0) this.iDivisionsX = value; }
137         }
138         
public int DivisionsY
139         {
140             
get { return this.iDivisionsY; }
141             
set { if (value > 0) this.iDivisionsY = value; }
142         }
143
144         
public double ScaleX
145         {
146             
get { return this.dScaleX; }
147             
set { if (value != 0) this.dScaleX = value; }
148         }
149         
public double ScaleY
150         {
151             
get { return this.dScaleY; }
152             
set { if (value != 0) this.dScaleY = value; }
153         }
154
155         
public double ForwardX
156         {
157             
get { return this.dForwardX; }
158             
set { this.dForwardX = value; }
159         }
160         
public double ForwardY
161         {
162             
get { return this.dForwardY; }
163             
set { this.dForwardY = value; }
164         }
165
166         
public int PrintStepX
167         {
168             
get { return this.iPrintStepX; }
169             
set { if (value > 0) this.iPrintStepX = value; }
170         }
171         
public int PrintStepY
172         {
173             
get { return this.iPrintStepY; }
174             
set { if (value > 0) this.iPrintStepY = value; }
175         }
176
177         
public int PolarSensitivity
178         {
179             
get { return this.iPolarSensitivity; }
180             
set { if (value > 0) this.iPolarSensitivity = value; }
181         }
182
183         
public bool Grids
184         {
185             
get { return this.bGrids; }
186             
set { this.bGrids = value; }
187         }
188
189         
public bool DisplayText
190         {
191             
get { return bDisplayText; }
192             
set { bDisplayText = value; }
193         }
194
195         
public GraphMode GraphMode
196         {
197             
get { return graphMode; }
198             
set { graphMode = value; }
199         }
200
201         
public int PenWidth
202         {
203             
get { return iPenWidth; }
204             
set { iPenWidth = value; }
205         }
206
207         
#endregion
208
209         
#region Plotting Functions
210         
void PlotGraph(Graphics g)
211         {
212             DisplayScale(g);
213             
if (this.bDisplayText)
214                 DisplayExpressionsText(g);
215
216             
double X, Y;
217             
double dPointX, dPointY;
218             
double dLeastStepX, dLeastStepY;
219             
double dMin, dMax, dStep;
220             
int i;
221
222             
//(X1,Y1) is the previous point ploted, (X2,Y2) is the current point to plot. (we will join both to have our
223             
// graph continuous).
224             
float X1 = 0, Y1 = 0, X2 = 0, Y2 = 0;
225             
//This variable controls whether our graph should be continuous or not
226             
bool bContinuity = false;
227
228             
//divide scale with its length(pixels) to get increment per pixel
229             dLeastStepX = dScaleX / iLengthScale;
230             dLeastStepY = dScaleY / iLengthScale;
231
232             
//prepare variables for loop
233             
if (graphMode == GraphMode.Polar)
234             {
235                 dMin = -Math.PI;
236                 dMax = Math.PI;
237                 dStep = dScaleX / iPolarSensitivity;
238             }
239             
else //if (Rectangular Mode)
240             {
241                 dStep = dLeastStepX;
242                 dMin = -dScaleX + dForwardX;
243                 dMax = dScaleX + dForwardX;
244             }
245
246
247             
for (i = 0; i < this.expressions.Count; i++)
248             {
249                 
//check if expression needs to be drawn and is valid
250                 
if (expVisible[i] == true && expressions[i].IsValid == true)
251                 {
252                     bContinuity =
false;
253                     
for (X = dMin; X != dMax; X += dStep)
254                     {
255                         
if (dScaleX < 0 && X < dMax)
256                             
break;
257                         
if (dScaleX > 0 && X > dMax)
258                             
break;
259                         
try
260                         {
261                             
//evaluate expression[i] at point: X
262                             Y = expressions[i].Evaluate(X);
263                             
if (double.IsNaN(Y))
264                             {
265                                 
//break continuity in graph if expression returned a NaN
266                                 bContinuity =
false;
267                                 
continue;
268                             }
269
270                             
//get points to plot
271                             
if (graphMode == GraphMode.Polar)
272                             {
273                                 dPointX = Y * Math.Cos(X) / dLeastStepX;
274                                 dPointY = Y * Math.Sin(X) / dLeastStepY;
275                             }
276                             
else // if (Rectangular mode;
277                             {
278                                 dPointX = X / dLeastStepX;
279                                 dPointY = Y / dLeastStepY;
280                             }
281
282                             
//check if the point to be plotted lies inside our visible area(i.e. inside our current axes ranges)
283                             
if ((iOriginY - dPointY + dForwardY / dLeastStepY) < iOriginY - iLengthScale
284                                 || (iOriginY - dPointY + dForwardY / dLeastStepY) > iOriginY + iLengthScale
285                                 || (iOriginX + dPointX - dForwardX / dLeastStepX) < iOriginX - iLengthScale
286                                 || (iOriginX + dPointX - dForwardX / dLeastStepX) > iOriginX + iLengthScale)
287                             {
288                                 
//the point lies outside our current scale so break continuity
289                                 bContinuity =
false;
290                                 
continue;
291                             }
292
293                             
//get coordinates for currently evaluated point
294                             X2 = (
float)(iOriginX + dPointX - dForwardX / dLeastStepX);
295                             Y2 = (
float)(iOriginY - dPointY + dForwardY / dLeastStepY);
296
297                             
//if graph should not be continuous
298                             
if (bContinuity == false)
299                             {
300                                 X1 = X2;
301                                 Y1 = Y2;
302                                 
// the graph should be continuous afterwards since the current evaluated value is valid
303                                 
// and can be plot within our axes range
304                                 bContinuity =
true;
305
306                             }
307
308                             
//join points (X1,Y1) and (X2,Y2)
309                             g.DrawLine(
new Pen(expColors[i], iPenWidth), new PointF(X1, Y1), new PointF(X2, Y2));
310
311                             
//get current values into X1,Y1
312                             X1 = X2;
313                             Y1 = Y2;
314                         }
315                         
catch
316                         {
317                             bContinuity =
false;
318                             
continue;
319                         }
320
321                     }
322                 }
323             }
324         }
325
326         
void DisplayScale(Graphics g)
327         {
328             
//axes lines
329             g.DrawLine(
new Pen(Color.Black, 2),
330                 
new Point(iOriginX - iLengthScale, iOriginY),
331                 
new Point(iOriginX + iLengthScale, iOriginY));
332
333             g.DrawLine(
new Pen(Color.Black, 2),
334                 
new Point(iOriginX, iOriginY - iLengthScale),
335                 
new Point(iOriginX, iOriginY + iLengthScale));
336
337             
int i;
338             
double dValue;
339             
string strValue;
340
341             
float cordX, cordY;
342
343             
//X-axis values
344             dValue = -dScaleX + dForwardX;
345             
for (i = -iDivisionsX; i <= iDivisionsX; i++)
346             {
347                 g.DrawLine(
new Pen(Color.Gray, 1),
348                     
new PointF((float)(iOriginX + (dValue - dForwardX) * iLengthScale / dScaleX), iOriginY - iLengthBox),
349                     
new PointF((float)(iOriginX + (dValue - dForwardX) * iLengthScale / dScaleX), iOriginY + iLengthBox));
350                 
if (i % iPrintStepX == 0 && i != 0)
351                 {
352                     strValue = Math.Round(dValue,
3).ToString();
353                     cordX = (
float)(iOriginX + (dValue - dForwardX) * iLengthScale / dScaleX - 6 - (strValue.Length - 2) * 5);
354                     cordY = (
float)(iOriginY + 10);
355                     g.DrawString(strValue,
new Font("Arial", 8), new SolidBrush(Color.Black), cordX, cordY);
356                 }
357                 dValue = dValue + dScaleX / iDivisionsX;
358             }
359
360
361             
//Y-axis values
362             dValue = -dScaleY + dForwardY;
363             
for (i = -iDivisionsY; i <= iDivisionsY; i++)
364             {
365                 g.DrawLine(
new Pen(Color.Gray, 1),
366                     
new PointF(iOriginX - iLengthBox, (float)(iOriginY + (dValue - dForwardY) * iLengthScale / dScaleY)),
367                     
new PointF(iOriginX + iLengthBox, (float)(iOriginY + (dValue - dForwardY) * iLengthScale / dScaleY)));
368                 
if (i % iPrintStepY == 0 && i != 0)
369                 {
370                     strValue = Math.Round(dValue,
3).ToString();
371                     cordX = (
float)(iOriginX - 20 - (strValue.Length) * 4);
372                     cordY = (
float)(iOriginY - (dValue - dForwardY) * iLengthScale / dScaleY - 7);
373                     
if (this.iLengthBox == this.iLengthScale)
374                         cordY +=
6;
375                     g.DrawString(strValue,
new Font("Arial", 8), new SolidBrush(Color.Black), cordX, cordY);
376                 }
377                 dValue = dValue + dScaleY / iDivisionsY;
378             }
379
380             
if (graphMode == GraphMode.Polar)
381             {
382                 g.DrawEllipse(
new Pen(Color.Black, 1), iOriginX - iLengthScale, iOriginY - (float)(iLengthScale * dScaleX / dScaleY), iLengthScale*2, (float)(iLengthScale * dScaleX / dScaleY)*2);
383                 
for (dValue = 0; dValue <= 2 * Math.PI; dValue += Math.PI / 6)
384                 {
385                     g.DrawLine(
new Pen(Color.Black, 1), new Point(iOriginX, iOriginY),
386                         
new PointF((float)(iOriginX + iLengthScale * Math.Cos(dValue)), (float)(iOriginY + iLengthScale * Math.Sin(dValue))));
387                 }
388             }
389         }
390
391         
void DisplayExpressionsText(Graphics g)
392         {
393             
int line = 0;
394             
for (int i = 0; i < this.expressions.Count; i++)
395             {
396                 
if (expVisible[i] == true)
397                 {
398                     
if (expressions[i].IsValid)
399                         g.DrawString(expressions[i].ExpressionText,
new Font("Arial", 10), new SolidBrush(expColors[i]), 10, 10 + 18 * line);
400                     
else
401                         g.DrawString(
"ERROR: " + expressions[i].ExpressionText, new Font("Arial", 10), new SolidBrush(expColors[i]), 10, 10 + 18 * line);
402                     line++;
403                 }
404             }
405         }
406
407         
void InitializePrintDoc()
408         {
409             
this.printDoc = new PrintDocument();
410             
this.printDoc.OriginAtMargins = true;
411             
this.printDoc.DefaultPageSettings.Margins.Left = 200;
412             
this.printDoc.DefaultPageSettings.Margins.Top = 100;
413             
this.printDoc.DocumentName = "Graph Plotter by Syed Mehroz Alam";
414             
this.printDoc.PrintPage += delegate(object sender, PrintPageEventArgs e) { PlotGraph(e.Graphics); };
415         }
416
417         
#endregion
418
419         
#region Public functions for expression management
420
421         
public void AddExpression(IEvaluatable expression, Color color, bool visible)
422         {
423             expressions.Add(expression);
424             expColors.Add(color);
425             expVisible.Add(visible);
426         }
427         
public bool RemoveExpression(IEvaluatable expression)
428         {
429             
int index = expressions.IndexOf(expression);
430             
if (index == -1)
431                 
return false;
432             expressions.RemoveAt(index);
433             expColors.RemoveAt(index);
434             expVisible.RemoveAt(index);
435             
return true;
436         }
437         
public void RemoveExpressionAt(int index)
438         {
439             
// can throw OutOfRangeException
440             expressions.RemoveAt(index);
441             expColors.RemoveAt(index);
442             expVisible.RemoveAt(index);
443         }
444         
public void RemoveAllExpressions()
445         {
446             
this.expressions.Clear();
447             
this.expColors.Clear();
448             
this.expVisible.Clear();
449         }
450
451         
public IEvaluatable GetExpression(int index)
452         {
453             
// can throw OutOfRangeException
454             
return expressions[index];
455         }
456         
public Color GetExpressionColor(int index)
457         {
458             
// can throw OutOfRangeException
459             
return expColors[index];
460         }
461         
public bool GetExpressionVisibility(int index)
462         {
463             
// can throw OutOfRangeException
464             
return expVisible[index];
465         }
466
467         
public void SetExpression(int index, IEvaluatable expression)
468         {
469             
// can throw OutOfRangeException
470             
this.expressions[index]=expression;
471         }
472         
public void SetExpressionColor(int index, Color color)
473         {
474             
// can throw OutOfRangeException
475             
this.expColors[index]=color;
476         }
477         
public void SetExpressionVisibility(int index, bool visibility)
478         {
479             
// can throw OutOfRangeException
480             
this.expVisible[index]=visibility;
481         }
482
483         
#endregion
484
485         
#region Public functions for graph management
486
487         
public void SetRangeX(double startX, double endX)
488         {
489             
this.dScaleX = (endX - startX) / 2;
490             
this.dForwardX = (endX + startX) / 2;
491         }
492         
public void SetRangeY(double startY, double endY)
493         {
494             
this.dScaleY = (endY - startY) / 2;
495             
this.dForwardY = (endY + startY) / 2;
496         }
497         
498         
public void RestoreDefaults()
499         {
500             
this.dScaleX = this.dScaleY = 10;
501             
this.dForwardX = this.dForwardY = 0;
502             
this.iDivisionsX=this.iDivisionsY = 5;
503             
this.iPrintStepX = this.iPrintStepY = 1;
504             
this.bGrids = false;
505             
this.iPolarSensitivity = 100;
506         }
507
508         
public void ToggleGrids()
509         {
510             
this.bGrids = (!bGrids);
511         }
512
513         
public double[] GetValues(double x)
514         {
515             
double[] result = new double[expressions.Count];
516             
for (int i = 0; i < this.expressions.Count; i++)
517                 
if (this.expressions[i].IsValid)
518                     result[i] =
this.expressions[i].Evaluate(x);
519             
return result;
520         }
521
522         
public Bitmap GetGraphBitmap()
523         {
524             Bitmap bmpSnap =
new Bitmap(this.Width, this.Height);
525             DrawToBitmap(bmpSnap,
new Rectangle(0, 0, this.Width, this.Height));
526             
return bmpSnap;
527         }
528
529         
public void CopyToClipboard()
530         {
531             Clipboard.SetImage(GetGraphBitmap());
532         }
533
534         
public void MoveLeft(int divisions)
535         {
536             
this.dForwardX -= divisions * this.dScaleX / this.iDivisionsX;
537         }
538         
public void MoveRight(int divisions)
539         {
540             
this.dForwardX += divisions * this.dScaleX / this.iDivisionsX;
541         }
542         
public void MoveUp(int divisions)
543         {
544             
this.dForwardY += divisions * this.dScaleY / this.iDivisionsY;
545         }
546         
public void MoveDown(int divisions)
547         {
548             
this.dForwardY -= divisions * this.dScaleY / this.iDivisionsY;
549         }
550
551         
public void ZoomInX()
552         {
553             
this.dScaleX = DecreaseScale(this.dScaleX);
554         }
555         
public void ZoomInY()
556         {
557             
this.dScaleY = DecreaseScale(this.dScaleY);
558         }
559         
public void ZoomOutX()
560         {
561             
this.dScaleX = IncreaseScale(this.dScaleX);
562         }
563         
public void ZoomOutY()
564         {
565             
this.dScaleY = IncreaseScale(this.dScaleY);
566         }
567
568         
public void ZoomIn()
569         {
570             ZoomInX();
571             ZoomInY();
572         }
573         
public void ZoomOut()
574         {
575             ZoomOutX();
576             ZoomOutY();
577         }
578
579         
#endregion
580
581     }
582 }



Phần mềm vẽ đồ thị C# 6.577 lượt xem

Gõ tìm kiếm nhanh...